use std::fs::{File, OpenOptions};
use std::io::Write;
use std::os::unix::fs::FileExt;
use std::sync::{Arc};
use crate::fio::IOManager;
use parking_lot::RwLock;
use thiserror::Error;
use log::error;
use crate::errors::{Errors, Result};

// FileIO 标准文件IO
pub struct FileIO {
    /// 系统文件描述符
    fd : Arc<RwLock<File>>,
}
fn NewFileIOManager(fileName : String) -> FileIO {
    let fd = File::open(fileName).unwrap();
    FileIO {
        fd : Arc::new(RwLock::new(fd)),
    }
}

impl FileIO {
    pub fn new(file_name : &str) ->Result<Self> {
        match OpenOptions::new().create(true).read(true).write(true).append(true).open(file_name)
        {
            Ok(file) => {
                return Ok(FileIO {fd : Arc::new(RwLock::new(file))});
            },
            Err(e) => {
                error!("failed to open data file: {}" , e);
                Err(Errors::FailedToOpenDataFile)
            }
        }
    }
}


impl IOManager for FileIO {
    fn read(&self, bytes: &mut [u8], offset: u64) -> crate::errors::Result<usize> {
        let read_guard = self.fd.read();
        let read_res = read_guard.read_at(bytes, offset);
        match read_res {
            Ok(parking_lot) => {
                return Ok(parking_lot);
            }
            Err(e) => {
                error!("read file error: {}", e);
                return Err(Errors::FailedToReadDataFile);
            }
        }
    }
    fn write(&self, buf: &[u8]) -> Result<usize> {
        let mut fd = self.fd.write();
        match fd.write(buf) {
            Ok(n) => { Ok(n) }
            Err(e) => {
                error!("write file error: {}", e);
                return Err(Errors::FailedToWriteDataFile);
            }
        }
    }

    fn close(&self) -> Result<()> {  // 加 &mut
        let fd = self.fd.write();
        if let Err(e) = fd.sync_all() {
            error!("sync file error: {}", e);
            return Err(Errors::FailedToSyncDataFile);
        }
        Ok(())
    }
    fn sync(&self) -> crate::errors::Result<()> {
        if let Err(e) =  self.fd.read().sync_all() {
            error!{"sync file error: {}",e }
            return Err(Errors::FailedToSyncDataFile);
        }
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use std::fs;
    use super::*;
    #[test]
    fn test_file_io() {
        let file_io = FileIO::new("test.txt");
        assert!(file_io.is_ok());
        let  fio = file_io.unwrap();
       // let res1 = file_io.write(b"hello world");
        let res1 = fio.write("hello world".as_bytes());
        assert!(res1.is_ok());
        let result = fs::remove_file("test.txt");
        assert!(result.is_ok());


    }
    #[test]
    fn test_file_read() {
        let fio_path = FileIO::new("test.txt");
        assert!(fio_path.is_ok());
        let  file_io = fio_path.ok().unwrap();
        let mut buf = [0u8; 5];
        let  result = file_io.write("key-a".as_bytes());
        assert!(result.is_ok());

        let result1 = file_io.read(&mut buf, 0);
        assert!(result1.is_ok());

        let result2 = fs::remove_file("test.txt");
        assert!(result2.is_ok());
    }
    #[test]
    fn test_file_sync() {
        let fio_path = FileIO::new("test.txt");
        assert!(fio_path.is_ok());
        let  file_io = fio_path.ok().unwrap();
        let  result = file_io.write("key-a".as_bytes());
        assert!(result.is_ok());
        let result1 = file_io.sync();
        assert!(result1.is_ok());


        let result2 = fs::remove_file("test.txt");
        assert!(result2.is_ok());
    }
}

